// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Xml.XPath;

namespace Microsoft.TeamFoundation.Migration.Toolkit.Wit
{
    /// <summary>
    /// Metadata description.
    /// </summary>
    [Flags]
    public enum MetadataTypes
    {
        None = 0x00,                    // No metadata types
        All = Lists | Accounts | Types, // All types

        Lists = 0x01,                   // Global lists
        Accounts = 0x02,                // Accounts (global- and project-scoped groups)
        Types = 0x04,                   // Work item types
    };

    /// <summary>
    /// TFS 2 TFS metadata synchronization policy.
    /// </summary>
    public class TfsMetadataPolicy
    {
        private MetadataTypes m_types;                      // Types that should be synchronized
        private ReadOnlyCollection<string> m_ignoredTypes;  // Names of work item types that should be ignored.
        private ReadOnlyCollection<string> m_ignoredLists;  // Names of global lists that should be ignored.

        /// <summary>
        /// Returns types that should be synchronized.
        /// </summary>
        public MetadataTypes Types
        {
            get { return m_types; }
            internal set
            {
                m_types = value;
            }
        }

        /// <summary>
        /// Returns names of work item types that should be ignored.
        /// </summary>
        public ReadOnlyCollection<string> IgnoredTypes { get { return m_ignoredTypes; } }

        /// <summary>
        /// Returns names of global lists that should be ignored.
        /// </summary>
        public ReadOnlyCollection<string> IgnoredLists { get { return m_ignoredLists; } }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="nav">Navigator, positioned to the policy</param>
        internal TfsMetadataPolicy(
            XPathNavigator nav)
        {
            List<string> ignoredTypes;
            List<string> ignoredLists;
            if (nav != null)
            {
                m_types = TranslateTypes(nav.GetAttribute("types", string.Empty));
                ignoredTypes = LoadList(nav.Select("IgnoredTypes/Name"));
                ignoredLists = LoadList(nav.Select("IgnoredLists/Name"));
            }
            else
            {
                ignoredLists = new List<string>();
                ignoredTypes = new List<string>();
                m_types = MetadataTypes.All;
            }
            m_ignoredTypes = ignoredTypes.AsReadOnly();
            m_ignoredLists = ignoredLists.AsReadOnly();
        }

        /// <summary>
        /// Translates XML metadata types into a set of flags.
        /// </summary>
        /// <param name="value">Value to translate</param>
        /// <returns>Set of flags</returns>
        private static MetadataTypes TranslateTypes(
            string value)
        {
            string[] names = value.Split(' ');
            MetadataTypes flags = MetadataTypes.None;

            for (int i = 0; i < names.Length; i++)
            {
                switch (names[i])
                {
                    case "types": flags |= MetadataTypes.Types; break;
                    case "lists": flags |= MetadataTypes.Lists; break;
                    case "accounts": flags |= MetadataTypes.Accounts; break;
                    case "all": flags |= MetadataTypes.All; break;

                    default:
                        Debug.Assert(string.IsNullOrEmpty(names[i]), "Unsupported metadata type!");
                        break;
                }
            }
            return flags;
        }

        /// <summary>
        /// Populates list with items from the XML.
        /// </summary>
        /// <param name="list">List to populate</param>
        /// <returns>Collection of strings</returns>
        private static List<string> LoadList(
            XPathNodeIterator nodes)
        {
            List<string> list = new List<string>();
            foreach (XPathNavigator nav in nodes)
            {
                string name = nav.GetAttribute("value", string.Empty);
                list.Add(name);
            }

            // Sort the list
            list.Sort(StringComparer.InvariantCultureIgnoreCase);
            return list;
        }
    }
}
